package org.biogroovy.cabio

import javax.xml.namespace.QName
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPath
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory

import org.biogroovy.io.AbsXmlReader
import org.biogroovy.io.IFetcher;
import org.biogroovy.models.Gene
import org.biogroovy.models.Pathway
import org.w3c.dom.Node
import org.w3c.dom.NodeList

/**
 * This class is responsible for reading pathways from the NCI's Pathway 
 * Interaction Database (PID).
 */
class PathwayReader extends AbsXmlReader<Pathway>{
	
	private static final String DATABASE_NAME = "ncipid";

	/**
	 * A map of XPath expressions used to extract data from the XML document
	 */
	private static final Map<String, String> XPATH_MAP = [
		description:'/queryResponse/field[@name="description"]',
		id:'/queryResponse/field[@name="id"]',
		name:'/queryResponse/field[@name="name"]'
	];


	/**
	 * A map of Node types used to determine the type of data to return when 
	 * parsing specific elements from the XML document
	 */
	private static final Map<String, QName> NODE_TYPE_MAP = [
		description:XPathConstants.STRING,
		id:XPathConstants.STRING,
		name:XPathConstants.STRING
	];


	/**
	 * A map of Xpath expressions used in parsing Gene objects
	 */
	private static final Map<String, String> GENE_XPATH_MAP = [
		geneSymbol:'field[@name="symbol"]',
		geneName:'field[@name="fullName"]'
	];

	/**
	 * A map of Node types used in parsing Gene objects.
	 */
	private static final Map<String, QName> GENE_NODE_TYPE_MAP = [
		geneSymbol:XPathConstants.STRING,
		geneName:XPathConstants.STRING
	];

	@Override
	public Pathway fetch(String pathwayId) throws IOException{
		URL url = getUrl(pathwayId)
		return read(url.openStream());
	}

	@Override
	public Pathway read(InputStream inputStream) throws IOException{
		def builder  = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Node root     = (Node)builder.parse(inputStream).documentElement
		
		Pathway pathway = new Pathway();
		parse(pathway, root)

		root = null;
		builder = null;
		return pathway;
	}

	/**
	 * Gets the genes found in a given pathway.
	 * 
	 * @param pathwayId	The pathway id.
	 * @return  a list of Gene objects.
	 */
	public List<Gene> readList(String pathwayId){
		URL url = getUrl(pathwayId, null)
		return readList(url.openStream())
	}

	/**
	 * Gets the genes found in an input stream.
	 * @param inputStream	The input stream containing the gene xml data.
	 * @return	a list of Gene objects.
	 */
	public List<Gene> readList(InputStream inputStream){
		List<Gene> geneList = new ArrayList<Gene>();

		def builder  = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		def root     = builder.parse(inputStream).documentElement

		XPath xpath = XPathFactory.newInstance().newXPath();
		NodeList nodeList = xpath.evaluate("//class[@name='gov.nih.nci.cabio.domain.Gene']", root, XPathConstants.NODESET);
		println nodeList.getLength()
		for(int i=0; i < nodeList.getLength(); i++){
			Node node = nodeList.item(i)
			Gene gene = new Gene();
			parseData(node, gene, GENE_XPATH_MAP, GENE_NODE_TYPE_MAP);
			geneList.add(gene);
			println "gene: ${gene}";
		}

		builder = null;
		root = null;

		return geneList;
	}




	@Override
	public void parse(Pathway pathway, Node node) {
		parseData(node, pathway, XPATH_MAP, NODE_TYPE_MAP);
	}


	@Override
	public URL getUrl(String pathwayId, Map<String, String> paramMap) {
		String url =  CaBioURLFactory.getURL( CaBioURLFactory.GENES_IN_PATHWAY, [pathwayId:pathwayId]);
		return new URL(url);
	}

	@Override
	public String getDatabaseName() {
		return DATABASE_NAME;
	}

	@Override
	public List<Pathway> fetchAll(String id) throws IOException {
		// TODO implement the method
		return null;
	}

	@Override
	public IFetcher<Pathway> getNewInstance() {
		return new PathwayReader();
	}


}
